/**
 * @addtogroup FXCRT
 * @{
 */

/**
 * @file
 * @brief Fixed precision number processing.
 *
 * Fixed precision number operations:\n
 *	We support FIX24.8 and FIX16.16 formats. Most numbers are stored in FIX24.8 format,
 * with some in FIX16.16 (like coefficients for affine matrix).
 *
 *  For intermediate operation, FIX32.32 format is used to preserve precision and range.
 * 
 *  We choose to not use classes with overloaded operators to implement FIX formats, because
 * the GCC compiler we use for many mobile platforms doesn't optimize well for overloaded operators.
 */

#ifndef _FX_FIX_H_
#define _FX_FIX_H_

#if 0 //#ifdef _USE_FIX_
	typedef int FX_FIX8;
	typedef int FX_FIX16;
	typedef FX_INT64 FX_FIX32;

	typedef FX_FIX8 FX_FIXFLOAT;
	typedef FX_FIX16 FX_FIXFLOAT16;
	typedef FX_FIX32 FX_FIXFLOAT32;
	typedef FX_FIX8 FX_FIXDOUBLE;
	typedef FX_FIX16 FX_FIXDOUBLE16;
	typedef FX_FIX32 FX_FIXDOUBLE32;

	#define FIX8_ONE	0x100
	#define FIX16_ONE	0x10000
	#define FIX32_ONE	((FX_INT64)1 << 32)
	#define FIX8_HALF	0x80
	#define FIX16_HALF	0x8000

	#ifndef _MSC_VER
	const FX_INT64 FIXFLOAT32_PI = 13493037704LL;
	#else
	const FX_INT64 FIXFLOAT32_PI = (FX_INT64)13493037704;
	#endif

	/* Conversion between different precision */
	#define fix0_to_8(a) ((a) << 8)
	#define fix0_to_16(a) ((a) << 16)
	#define fix0_to_32(a) ((FX_INT64)(a) << 32)
	#define fix8_to_0(a) ((a) >> 8)
	#define fix8_to_16(a) ((a) << 8)
	#define fix8_to_32(a) (((FX_INT64)(a)) << 24)
	#define fix16_to_8(a) ((a) >> 8)
	#define fix16_to_32(a) (((FX_INT64)(a)) << 16)
	#define fix32_to_0(a) (int)((a) >> 32)
	#define fix32_to_8(a) ((int)((a) >> 24))
	#define fix32_to_16(a) ((int)((a) >> 16))

	#define fix8_to_float(a) ((FX_FLOAT)(a) / 256)
	#define fix16_to_float(a) ((FX_FLOAT)(a) / 65536)
	#define fix32_to_float(a) ((FX_FLOAT)(a) / 4294967296.0f)
	#define float_to_fix8(a) (FXSYS_round((a) * 256))
	#define float_to_fix16(a) (FXSYS_round((a) * 65536))
	#define float_to_fix32(a) ((FX_INT64)FXSYS_round((a)*65536) << 16)

	int		FXSYS_ceil(FX_FIX8 a);
	int		FXSYS_ceil(FX_FIX16 a);
	int		FXSYS_ceil(FX_FIX32 a);
	int		FXSYS_floor(FX_FIX8 a);
	int		FXSYS_floor(FX_FIX16 a);
	int		FXSYS_floor(FX_FIX32 a);
	int		FXSYS_round(FX_FIX8 a);
	int		FXSYS_round(FX_FIX16 a);
	int		FXSYS_round(FX_FIX32 a);

	FX_FIX8 fixmul_8_8_to_8(FX_FIX8 a, FX_FIX8 b);
	FX_FIX32 fixmul_8_8_to_32(FX_FIX8 a, FX_FIX8 b);
	FX_FIX8 fixmul_8_16_to_8(FX_FIX8 a, FX_FIX16 b);
	FX_FIX32 fixmul_8_16_to_32(FX_FIX8 a, FX_FIX16 b);
	FX_FIX8 fixmul_8_32_to_8(FX_FIX8 a, FX_FIX32 b);
	FX_FIX32 fixmul_8_32_to_32(FX_FIX8 a, FX_FIX32 b);
	FX_FIX16 fixmul_16_16_to_16(FX_FIX8 a, FX_FIX16 b);
	FX_FIX32 fixmul_16_16_to_32(FX_FIX16 a, FX_FIX16 b);
	FX_FIX32 fixmul_32_32_to_32(FX_FIX32 a, FX_FIX32 b);

	FX_FIX32 fixdiv_32_32_to_32(FX_FIX32 a, FX_FIX32 b);
	FX_FIX32 fixdiv_8_8_to_32(FX_FIX8 a, FX_FIX8 b);

	FX_FIX8 fixmuldiv_8(FX_FIX8 a, FX_FIX8 b, FX_FIX8 c);		// a * b / c

	FX_FIX16 FXSYS_sqrt(FX_FIX32 a);
	FX_FIX8 fixsqrt2_16_16_to_8(FX_FIX16 a, FX_FIX16 b);
	FX_FIX8 fixsqrt2_8_8_to_8(FX_FIX8 a, FX_FIX8 b);

	#define	FXSYS_fabs(a) ((a) < 0 ? -(a) : (a))

	FX_FIX8	FX_atof(FX_BSTR str);
	class CFX_ByteString;

	CFX_ByteString CFX_ByteString::FormatFloat(FX_FIX8 a);

	FX_FIX32 FXSYS_sin(FX_FIX32 radian);
	FX_FIX32 FXSYS_cos(FX_FIX32 radian);
	FX_FIX32 FXSYS_atan2(FX_FIX32 x, FX_FIX32 y);
	FX_FIX32 FXSYS_acos(FX_FIX32 x);
#else
	/** @brief FIX24.8 if _USE_FIX_ defined, otherwise floating point number. */
	typedef FX_FLOAT FX_FIXFLOAT;
	/** @brief FIX16.16 if _USE_FIX_ defined, otherwise floating point number. */
	typedef FX_FLOAT FX_FIXFLOAT16;
	/** @brief FIX32.32 if _USE_FIX_ defined, otherwise floating point number. */
	typedef FX_FLOAT FX_FIXFLOAT32;
	/** @brief FIX24.8 if _USE_FIX_ defined, otherwise double precision number. */
	typedef double FX_FIXDOUBLE;
	/** @brief FIX16.16 if _USE_FIX_ defined, otherwise double precision number. */
	typedef double FX_FIXDOUBLE16;
	/** @brief FIX32.32 if _USE_FIX_ defined, otherwise double precision number. */
	typedef double FX_FIXDOUBLE32;

	/**
		* @brief 0x100 if _USE_FIX_ defined, otherwise 1.0f.
		* @hideinitializer
		*/
	const FX_FLOAT FIX8_ONE = 1.0f;
	/**
		* @brief 0x10000 if _USE_FIX_ defined, otherwise 1.0f.
		* @hideinitializer
		*/
	const FX_FLOAT FIX16_ONE = 1.0f;
	/**
		* @brief 0x100000000 if _USE_FIX_ defined, otherwise 1.0f.
		* @hideinitializer
		*/
	const FX_FLOAT FIX32_ONE = 1.0f;
	/**
		* @brief 0x80 if _USE_FIX_ defined, otherwise 0.5f.
		* @hideinitializer
		*/
	const FX_FLOAT FIX8_HALF = 0.5f;
	/**
		* @brief 0x8000 if _USE_FIX_ defined, otherwise 0.54f.
		* @hideinitializer
		*/
	const FX_FLOAT FIX16_HALF = 0.5f;

	/**
		* @brief 13493037704 if _USE_FIX_ defined, otherwise 3.14159265358979323846f.
		* @hideinitializer
		*/
	const FX_FLOAT FIXFLOAT32_PI = FX_PI;

	/**
	 * @name Conversion between different precision
	 */
	/*@{*/

	/**
	 * @brief Convert an integer to FIX24.8.
	 * @hideinitializer
	 */
	#define fix0_to_8(a) ((FX_FLOAT)a)
	/**
	 * @brief Convert an integer to FIX16.16.
	 * @hideinitializer
	 */
	#define fix0_to_16(a) ((FX_FLOAT)a)
	/**
	 * @brief Convert an integer to FIX32.32.
	 * @hideinitializer
	 */
	#define fix0_to_32(a) ((FX_FLOAT)a)
	/**
	 * @brief Convert a FIX24.8 to an integer.
	 * @hideinitializer
	 */
	#define fix8_to_0(a) (int)(a)
	/**
	 * @brief Convert a FIX24.8 to FIX16.16.
	 * @hideinitializer
	 */
	#define fix8_to_16(a) (a)
	/**
	 * @brief Convert a FIX24.8 to FIX32.32.
	 * @hideinitializer
	 */
	#define fix8_to_32(a) (a)
	/**
	 * @brief Convert a FIX16.16 to FIX24.8.
	 * @hideinitializer
	 */
	#define fix16_to_8(a) (a)
	/**
	 * @brief Convert a FIX16.16 to FIX32.32.
	 * @hideinitializer
	 */
	#define fix16_to_32(a) (a)
	/**
	 * @brief Convert a FIX32.32 to an integer.
	 * @hideinitializer
	 */
	#define fix32_to_0(a) (int)(a)
	/**
	 * @brief Convert a FIX32.32 to FIX24.8.
	 * @hideinitializer
	 */
	#define fix32_to_8(a) (a)
	/**
	 * @brief Convert a FIX32.32 to FIX16.16.
	 * @hideinitializer
	 */
	#define fix32_to_16(a) (a)

	/*@}*/ 

	/**
	 * @name Conversion between floating-point and fix-point.
	 */
	/*@{*/

	/**
	 * @brief Convert a FIX24.8 to a floating point number.
	 * @hideinitializer
	 */
	#define fix8_to_float(a) (a)
	/**
	 * @brief Convert a FIX16.16 to a floating point number.
	 * @hideinitializer
	 */
	#define fix16_to_float(a) (a)
	/**
	 * @brief Convert a FIX32.32 to a floating point number.
	 * @hideinitializer
	 */
	#define fix32_to_float(a) (a)
	/**
	 * @brief Convert a floating point number to FIX24.8.
	 * @hideinitializer
	 */
	#define float_to_fix8(a) (a)
	/**
	 * @brief Convert a floating point number to FIX16.16.
	 * @hideinitializer
	 */
	#define float_to_fix16(a) (a)
	/**
	 * @brief Convert a floating point number to FIX32.32.
	 * @hideinitializer
	 */
	#define float_to_fix32(a) (a)

	/*@}*/ 

	/**
	 * @name Multiply and division operation.
	 */
	/*@{*/

	/**
	 * @brief Multiply two FIX24.8, result in FIX24.8.
	 * @hideinitializer
	 */
	#define fixmul_8_8_to_8(a, b) ((a) * (b))
	/**
	 * @brief Multiply two FIX24.8, result in FIX32.32.
	 * @hideinitializer
	 */
	#define fixmul_8_8_to_32(a, b) ((a) * (b))
	/**
	 * @brief Multiply a FIX24.8 and a FIX16.16, result in FIX24.8 
	 * @hideinitializer
	 */
	#define fixmul_8_16_to_8(a, b) ((a) * (b))
	/**
	 * @brief Multiply a FIX24.8 and a FIX16.16, result in FIX32.32.
	 * @hideinitializer
	 */
	#define fixmul_8_16_to_32(a, b) ((a) * (b))
	/**
	 * @brief Multiply a FIX24.8 and a FIX32.32, result in FIX24.8.
	 * @hideinitializer
	 */
	#define fixmul_8_32_to_8(a, b) ((a) * (b))
	/**
	 * @brief Multiply a FIX24.8 and a FIX32.32, result in FIX32.32.
	 * @hideinitializer
	 */
	#define fixmul_8_32_to_32(a, b) ((a) * (b))
	/**
	 * @brief Multiply two FIX16.16, result in FIX16.16.
	 * @hideinitializer
	 */
	#define fixmul_16_16_to_16(a, b) ((a) * (b))
	/**
	 * @brief Multiply two FIX16.16, result in FIX32.32.
	 * @hideinitializer
	 */
	#define fixmul_16_16_to_32(a, b) ((a) * (b))
	/**
	 * @brief Multiply two FIX32.32, result in FIX32.32.
	 * @hideinitializer
	 */
	#define fixmul_32_32_to_32(a, b) ((a) * (b))

	/**
	 * @brief Division between two FIX24.8, result in FIX32.32.
	 * @hideinitializer
	 */
	#define fixdiv_8_8_to_32(a, b) ((a) / (b))
	/**
	 * @brief Division between two FIX32.32, result in FIX32.32.
	 * @hideinitializer
	 */
	#define fixdiv_32_32_to_32(a, b) ((a) / (b))

	/**
	 * @brief Fist do multiplication, then do division, a, b and c are FIX24.8, result in FIX24.8
	 * @hideinitializer
	 */
	#define fixmuldiv_8(a, b, c) ((a) * (b) / (c))

	/*@}*/

	/**
	 * @name Square root calculation
	 */
	/*@{*/

	/**
	 * @brief Calculate square root of FIX32.32, result in FIX16.16. 
	 * @hideinitializer
	 */
	#define fixsqrt_32_to_16(a) (FX_FLOAT)FXSYS_sqrt(a)
	/**
	 * @brief sqrt(a^2 + b^2), a and b are FIX24.8, result in FIX24.8
	 * @hideinitializer
	 */
	#define fixsqrt2_8_8_to_8(a, b) (FX_FLOAT)FXSYS_sqrt((a)*(a) + (b)*(b))
	/**
	 * @brief sqrt(a^2 + b^2), a and b are FIX16.16, result in FIX24.8
	 * @hideinitializer
	 */
	#define fixsqrt2_16_16_to_8(a, b) (FX_FLOAT)FXSYS_sqrt((a)*(a) + (b)*(b))

	/*@}*/

	/**
	 * @name Find ceiling, floor, nearest integer.
	 */
	/*@{*/

	/**
	 * @brief Get the ceiling of a FIX24.8.
	 * @hideinitializer
	 */
	#define fixceil_8(a) (int)FXSYS_ceil(a)
	/**
	 * @brief Get the ceiling of a FIX16.16.
	 * @hideinitializer
	 */
	#define fixceil_16(a) (int)FXSYS_ceil(a)
	/**
	 * @brief Get the ceiling of a FIX32.32.
	 * @hideinitializer
	 */
	#define fixceil_32(a) (int)FXSYS_ceil(a)
	/**
	 * @brief Get the floor of a FIX24.8.
	 * @hideinitializer
	 */
	#define fixfloor_8(a) (int)FXSYS_floor(a)
	/**
	 * @brief Get the floor of a FIX16.16.
	 * @hideinitializer
	 */
	#define fixfloor_16(a) (int)FXSYS_floor(a)
	/**
	 * @brief Get the floor of a FIX32.32.
	 * @hideinitializer
	 */
	#define fixfloor_32(a) (int)FXSYS_floor(a)
	/**
	 * @brief Get the round of a FIX24.8.
	 * @hideinitializer
	 */
	#define fixround_8(a) FXSYS_round(a)
	/**
	 * @brief Get the round of a FIX16.16.
	 * @hideinitializer
	 */
	#define fixround_16(a) FXSYS_round(a)
	/**
	 * @brief Get the round of a FIX32.32.
	 * @hideinitializer
	 */
	#define fixround_32(a) FXSYS_round(a)

	/*@}*/

	#if _FX_OS_ == _FX_WIN32_MOBILE_ || (_FX_OS_ == _FX_SYMBIAN_ && _FX_COMPILER_ == _FX_GCC_) || defined(_FX_NO_ANSIC_)
		inline FX_FLOAT fixabs(FX_FLOAT a) { return a < 0 ? -a : a; }
	#else
		/**
			* @brief Get the absolution of a number.
			* @hideinitializer
			*/
		#define fixabs(a) FXSYS_fabs(a)
	#endif

	/**
	 * @name Conversion between a ANSIC string and a FIX24.8 number
	 */
	/*@{*/

	/**
	 * @brief Convert a ANSIC string to a FIX24.8 number.
	 * @hideinitializer
	 */
	#define str_to_fix8(a) FX_atof(a)
	/**
	 * @brief Convert a FIX24.8 number to a ANSIC string.
	 * @hideinitializer
	 */
	#define fix8_to_str(a) CFX_ByteString::FormatFloat(a)

	/*@}*/

	/**
	 * @name Trigonometric function.
	 */
	/*@{*/

	/**
	 * @brief Calculate the sine value, input and output are all FIX32.32. 
	 * @hideinitializer
	 */
	#define fixsin(a) ((FX_FLOAT)FXSYS_sin(a))
	/**
	 * @brief Calculate the cosine value, input and output are all FIX32.32.
	 * @hideinitializer
	 */
	#define fixcos(a) ((FX_FLOAT)FXSYS_cos(a))
	/**
	 * @brief Calculate the arctangent value, input and output are all FIX32.32.
	 * @hideinitializer
	 */
	#define fixatan2(a, b) ((FX_FLOAT)FXSYS_atan2(a, b))
	/**
	 * @brief Calculate the arc-cosine value, input and output are all FIX32.32.
	 * @hideinitializer
	 */
	#define fixacos(a) ((FX_FLOAT)FXSYS_acos(a))

	/*@}*/
#endif

#endif //_FX_FIX_H_

/** @} */
